package com.zxp.server.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zxp.server.service.IUserService;
import com.zxp.server.util.token.JwtUtil;
import com.zxp.server.util.token.annotation.CheckToken;
import com.zxp.server.util.token.annotation.NoCheckToken;
import com.zxp.server.vo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
 * @ClassName: AuthenticationInterceptor
 * @Description: 拦截器
 */
public class AuthenticationInterceptor  implements HandlerInterceptor {

  @Autowired
  IUserService userService;

  @Override
  public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {

    // 从 http 请求头中取出 token
    String token = httpServletRequest.getHeader("authorization");
    // 如果不是映射到方法直接通过
    if (!(object instanceof HandlerMethod)) {
      return true;
    }

    HandlerMethod handlerMethod = (HandlerMethod) object;
    Method method = handlerMethod.getMethod();
    //检查是否有NoCheckToken注释，有则跳过认证
    if (method.isAnnotationPresent(NoCheckToken.class)) {
      NoCheckToken NoCheckToken = method.getAnnotation(NoCheckToken.class);
      if (NoCheckToken.required()) {
        return true;
      }
    }

    String userId = null;

    //检查是否有CheckToken注释
    if (method.isAnnotationPresent(CheckToken.class)) {
      CheckToken checkToken = method.getAnnotation(CheckToken.class);
      if (checkToken.required()) {
        // 执行认证
        if (token == null) {
          authenticationFailed(httpServletResponse);
          return false;
        }else {
          try {
            userId = JwtUtil.parseJWT(token).get("id").toString();
          } catch (Exception exception) {
            authenticationFailed(httpServletResponse);
            return false;
          }
        }

        // 获取 token 中的 user id
        User user = userService.findUserById(userId);
        if (user == null) {
          authenticationFailed(httpServletResponse);
          return false;
          //throw new RuntimeException("用户不存在，请重新登录");
        }
        String jwt = JwtUtil.isVerify(token, user);
        if (StringUtils.isEmpty(jwt)) {
          authenticationFailed(httpServletResponse);
          return false;
        }
        httpServletResponse.setHeader(JwtUtil.TOKEN,jwt);
        return true;
      }
    }
    return true;
  }
  @Override
  public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  }
  @Override
  public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  }

  //token认证失败的方法
  public static void  authenticationFailed(HttpServletResponse response) throws IOException {
    response.setCharacterEncoding("UTF-8");
    //设置数据格式为json格式
    response.setContentType("application/json");
    //拿到输出流
    PrintWriter out = response.getWriter();
    //未登录或失效
    Result error = Result.error("未登录或用户信息过期，请重新登录！");
    error.setState("unauthorize");
    out.write(new ObjectMapper().writeValueAsString(error));
    out.flush();
    out.close();
  }
}
